#region File Description
//-----------------------------------------------------------------------------
// Author: JCBDigger
// URL: http://Games.DiscoverThat.co.uk
// Modified from the samples provided by
// Microsoft XNA Community Game Platform
//-----------------------------------------------------------------------------
#endregion

using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Windows.Forms;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Specialized;
using AssetData;
using AssetContent;

namespace Engine
{
    /// <summary>
    /// Custom form provides the main user interface for the program.
    /// In this tool we used the designer to fill half the form with a
    /// ModelViewerControl.  Included a menu bar which provides the
    /// "File / Open..." option and added a tabed panel for changing settings.
    /// </summary>
    public partial class MainForm : Form
    {
        private const string unnamedEffect = "NoName";

        private ContentBuilder contentBuilder;
        private ContentManager contentManager;

        private string defaultFileFolder = "";
        public string DefaultFileFolder
        {
            get { return defaultFileFolder; }
        }

        private string lastLoadedFile = "";

        /// <summary>
        /// Constructs the main form.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            contentBuilder = new ContentBuilder();

            contentManager = new ContentManager(modelViewerControl.Services,
                                                contentBuilder.OutputDirectory);
            // A folder in the users MyDocuments
            defaultFileFolder = GetSavePath();

            UpdateMenuItemVisibility();

            modelViewerControl.IsMoving += new EventHandler<EventArgs>(modelViewerControl_IsMoving);
            modelViewerControl.Click += new EventHandler(modelViewerControl_Click);
            modelViewerControl.OnChangedEmitterList += new EventHandler<EventArgs>(modelViewerControl_OnChangedEmitters);
            modelViewerControl.OnChangedImageList += new EventHandler<EventArgs>(modelViewerControl_OnChangedImages);
            modelViewerControl.OnChangedParticleList += new EventHandler<EventArgs>(modelViewerControl_OnChangedParticles);

            comboImageName.SelectedIndexChanged += new EventHandler(comboImageName_SelectedIndexChanged);
            comboEmitterName.SelectedIndexChanged += new EventHandler(comboEmitterName_SelectedIndexChanged);
            comboEffectName.SelectedIndexChanged += new EventHandler(comboEffectName_SelectedIndexChanged);

        }

        
        //////////////////////////////////////////////////////////////////////
        //
        #region Setup
        //
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            string name = modelViewerControl.InitialiseParticles();
            ShowFloor(true);
            ShowAxes(true);
            modelViewerControl.PauseInput = false;
            menuStrip1.MenuActivate += new EventHandler(menuStrip1_MenuActivate);
            menuStrip1.MenuDeactivate += new EventHandler(menuStrip1_MenuDeactivate);

            UpdateEmitterList();
            UpdateParticleList();
            UpdateImagesList();

            ChangeSelectedParticleName(name);
            pictureTexture.BackColor = buttonWhite.BackColor;

            buttonSkyDefault.BackColor = modelViewerControl.BackColor;
            colourSkyCustom.ColourChanged += new EventHandler<EventArgs>(colourSkyCustom_ColourChanged);
            colourFloorCustom.ColourChanged += new EventHandler<EventArgs>(colourFloorCustom_ColourChanged);

            InitialiseEmitterValues();
        }

        private void menuStrip1_MenuDeactivate(object sender, EventArgs e)
        {
            PauseGameInput(false);
        }

        private void menuStrip1_MenuActivate(object sender, EventArgs e)
        {
            PauseGameInput(true);
        }

        private void PauseGameInput(bool change)
        {
            modelViewerControl.PauseInput = change;
        }

        private void modelViewerControl_Click(object sender, EventArgs e)
        {
            ParkCursor();
        }

        private void modelViewerControl_IsMoving(object sender, EventArgs e)
        {
            ParkCursor();
        }

        /// <summary>
        /// Move the cursor to an unused dialogue while the model is being moved
        /// this is to avoid unexpected menu changes
        /// </summary>
        public void ParkCursor()
        {
            modelViewerControl.Focus();
        }

        private void resetViewingPoint_Click(object sender, EventArgs e)
        {
            modelViewerControl.InitialiseCameraPosition();
        }

        private void buttonCameraDefault_Click(object sender, EventArgs e)
        {
            modelViewerControl.InitialiseCameraPosition();
        }

        // Camera Position: {X:-3.006086 Y:2.235103 Z:2.251045} Direction: {X:-0.6090534 Y:0.08865751 Z:0.7881585}
        private static readonly Vector3 fpCameraPosition = new Vector3(-3.006086f, 2.235103f, 2.251045f);
        private static readonly Vector3 fpCameraDirection = new Vector3(-0.6090534f, 0.08865751f, 0.7881585f);
        private void buttonCameraFirstPerson_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetCameraPosition(fpCameraPosition, fpCameraDirection);
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region File and Status
        //
        /// <summary>
        /// Event handler for the Exit menu option.
        /// </summary>
        private void ExitMenu_Click(object sender, EventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Display a message.
        /// At the moment this is in the debug Output window but this method
        /// could easilt be changed to display elsewhere.
        /// </summary>
        private void AddMessageLine(string message)
        {
            System.Diagnostics.Debug.WriteLine(message);
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region Load and Save Emitters

        private void saveEmittersMenu_Click(object sender, EventArgs e)
        {
            SaveEmitterDialogue("", modelViewerControl.GetEmittersSaveData());
        }

        /// <summary>
        /// Returns the name of the saved file.
        /// </summary>
        private string SaveEmitterDialogue(string suggestedFileName, List<string> data)
        {
            // Path to default location
            string pathToSaveFolder = defaultFileFolder;
            string fileName = ".emit";
            // If we have loaded a file use that for the path and the name
            if (string.IsNullOrEmpty(suggestedFileName))
            {
                suggestedFileName = Path.GetFileNameWithoutExtension(lastLoadedFile);
            }
            if (string.IsNullOrEmpty(suggestedFileName))
            {
                suggestedFileName = "Emitters";
            }
            string assetName = suggestedFileName;
            if (!string.IsNullOrEmpty(lastLoadedFile))
            {
                pathToSaveFolder = Path.GetDirectoryName(lastLoadedFile);
            }
            fileName = assetName + fileName;

            SaveFileDialog fileDialog = new SaveFileDialog();

            fileDialog.InitialDirectory = pathToSaveFolder;

            fileDialog.Title = "Save the emitter settings";

            fileDialog.FileName = fileName;

            fileDialog.Filter = "Emitter File (*.emit)|*.emit|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                SaveTextFile(fileDialog.FileName, data);
                return fileDialog.FileName;
            }
            return "";
        }

        private void LoadEmittersMenu()
        {
            // Find out what file we want to open
            OpenFileDialog fileDialog = new OpenFileDialog();

            fileDialog.InitialDirectory = defaultFileFolder;

            fileDialog.Title = "Load Emitter Settings";

            fileDialog.Filter = "Emitter Files (*.emit)|*.emit|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                lastLoadedFile = fileDialog.FileName;
                modelViewerControl.AddEmittersFromList(LoadTextFile(lastLoadedFile));
            }
            UpdateMenuItemVisibility();
        }

        private string[] LoadTextFile(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                return null;
            }

            Cursor = Cursors.WaitCursor;

            string[] result = File.ReadAllLines(fileName);

            Cursor = Cursors.Arrow;

            return result;
        }

        private void loadEmittersMenuItem_Click(object sender, EventArgs e)
        {
            LoadEmittersMenu();
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Load and Save Particles
        //
        private void saveParticleSettingsMenu_Click(object sender, EventArgs e)
        {
            ParticleSettings settings = FormSettings();
            SaveXMLDialogue(CurrentEffectName(), settings.GetClassInContentXMLFormat());
            modelViewerControl.RestartAllParticles();
        }
        /// <summary>
        /// Returns the name of the saved file.
        /// </summary>
        private string SaveXMLDialogue(string suggestedFileName, List<string> data)
        {
            // Path to default location
            string pathToSaveFolder = defaultFileFolder;
            string fileName = ".xml";
            // If we have loaded a file use that for the path and the name
            if (string.IsNullOrEmpty(suggestedFileName))
            {
                suggestedFileName = Path.GetFileNameWithoutExtension(lastLoadedFile);
            }
            if (string.IsNullOrEmpty(suggestedFileName))
            {
                suggestedFileName = "Particle";
            }
            string assetName = suggestedFileName;
            if (!string.IsNullOrEmpty(lastLoadedFile))
            {
                pathToSaveFolder = Path.GetDirectoryName(lastLoadedFile);
            }
            fileName = assetName + fileName;

            SaveFileDialog fileDialog = new SaveFileDialog();

            fileDialog.InitialDirectory = pathToSaveFolder;

            fileDialog.Title = "Save the particle settings";

            fileDialog.FileName = fileName;

            fileDialog.Filter = "XML File (*.xml)|*.xml|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                SaveTextFile(fileDialog.FileName, data);
                return fileDialog.FileName;
            }
            return "";
        }

        /// <summary>
        /// Used from various classes to save files
        /// </summary>
        public void SaveTextFile(string fileName, List<string> data)
        {
            if (data.Count < 1 || string.IsNullOrEmpty(fileName))
            {
                return;
            }

            Cursor = Cursors.WaitCursor;

            File.WriteAllLines(fileName, data);

            Cursor = Cursors.Arrow;

        }

        private void LoadParticleSettingsMenu_Click(object sender, EventArgs e)
        {
            // Find out what file we want to open
            OpenFileDialog fileDialog = new OpenFileDialog();

            fileDialog.InitialDirectory = defaultFileFolder;

            fileDialog.Title = "Load XML Particle Settings";

            fileDialog.Filter = "Settings Files (*.xml)|*.xml|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                lastLoadedFile = fileDialog.FileName;
                LoadXMLParticles(fileDialog.FileName);
            }
            UpdateMenuItemVisibility();
        }

        private void LoadXMLParticles(string fileName)
        {
            Cursor = Cursors.WaitCursor;
            // Looks better when displaying results
            fileName = ParseData.StandardiseFolderCharacters(fileName);
            // Clear the content manager so that a new model is loaded otherwise the same name cannot be loaded again!
            contentManager.Unload();
            // Tell the ContentBuilder what to build.
            contentBuilder.Clear();

            AddMessageLine("Loading XML Particle Settings file: " + fileName);
            contentBuilder.AddXMLContent(fileName, GlobalSettings.contentParticleName);

            // Build this new model data.
            string buildError = contentBuilder.Build();
            string buildWarnings = contentBuilder.Warnings();
            if (!string.IsNullOrEmpty(buildWarnings))
            {
                AddMessageLine(buildWarnings);
            }

            if (string.IsNullOrEmpty(buildError))
            {
                string result = "";
                // If the build succeeded, use the ContentManager to
                // load the temporary .xnb file that we just created.
                ParticleSettings settings = contentManager.Load<ParticleSettings>(GlobalSettings.contentParticleName);
                if (settings == null)
                {
                    result = "Settings failed to load!";
                }
                else
                {
                    string currentPath = Path.GetDirectoryName(fileName);
                    string imageName = settings.GetImageFileName();
                    ParticleImage image = null;
                    if (string.IsNullOrEmpty(imageName))
                    {
                        result = "No image specified in the settings!";
                    }
                    else
                    {
                        string imageFileName = Path.Combine(currentPath, imageName);
                        image = LoadParticleImage(imageFileName);
                    }
                    if (image == null)
                    {
                        result = "Image not loaded!";
                    }
                    result = AddAndDisplayNewSettings(fileName, settings, image);
                }
                if (!string.IsNullOrEmpty(result))
                {
                    AddMessageLine(result);
                }
            }
            else
            {
                // If the build failed, display an error message and log it
                AddMessageLine(buildError);
                MessageBox.Show(buildError, "Error");
            }

            Cursor = Cursors.Arrow;
        }



        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Load Images
        //
        private void LoadParticleTextureMenu_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();

            fileDialog.InitialDirectory = defaultFileFolder;

            fileDialog.Title = "Load Texture Image";

            fileDialog.Filter = "Image Files (*.png;*.tga)|*.png;*.tga|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                LoadParticleImage(fileDialog.FileName);
            }
            UpdateMenuItemVisibility();
        }

        /// <summary>
        /// Loads the image from file.
        /// </summary>
        private ParticleImage LoadParticleImage(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                AddMessageLine("No image file name specified!");
                return null;
            }
            Cursor = Cursors.WaitCursor;
            ParticleImage result = null;
            Texture2D image = null;
            // Looks better when displaying results
            fileName = ParseData.StandardiseFolderCharacters(fileName);
            // Clear the content manager so that a new model is loaded otherwise the same name cannot be loaded again!
            contentManager.Unload();
            // Tell the ContentBuilder what to build.
            contentBuilder.Clear();

            AddMessageLine("Loading Image file: " + fileName);
            contentBuilder.AddParticleTexture(fileName, GlobalSettings.contentImageName);

            // Build this new model data.
            string buildError = contentBuilder.Build();
            string buildWarnings = contentBuilder.Warnings();
            if (!string.IsNullOrEmpty(buildWarnings))
            {
                AddMessageLine(buildWarnings);
            }

            if (string.IsNullOrEmpty(buildError))
            {
                // If the build succeeded, use the ContentManager to
                // load the temporary .xnb file that we just created.
                image = contentManager.Load<Texture2D>(GlobalSettings.contentImageName);

                if (image == null)
                {
                    AddMessageLine("Image failed to load!");
                }
                else
                {
                    result = new ParticleImage(fileName, image);
                    modelViewerControl.AddOrUpdateImage(result);
                    Thread.Sleep(2);
                    DisplayImage(result);
                }
            }
            else
            {
                // If the build failed, display an error message and log it
                AddMessageLine(buildError);
                MessageBox.Show(buildError, "Error");
            }

            Cursor = Cursors.Arrow;
            return result;
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region View and Help
        //
        // Remember what was set between changing views
        private bool previousShowFloor = true;

        private void showFloor_Click(object sender, EventArgs e)
        {
            ShowFloor(!showFloorMenuItem.Checked);
            // Remember the current setting so we can change back after changing views
            previousShowFloor = showFloorMenuItem.Checked;
        }

        public void ShowFloor(bool show)
        {
            if (show && modelViewerControl.Floor == null)
            {
                Loader contentLoad = new Loader(modelViewerControl.Services);
                modelViewerControl.SetFloor(contentLoad.GetModel("grid100x100"));
            }
            showFloorMenuItem.Checked = show;
            showFloorMenuItem.Checked = modelViewerControl.ShowFloor(show);
        }


        private void showAxesMenuItem_Click(object sender, EventArgs e)
        {
            ShowAxes(!showAxesMenuItem.Checked);
        }

        private void ShowAxes(bool show)
        {
            if (show && !modelViewerControl.IsAxisFontLoaded())
            {
                Loader contentLoad = new Loader(modelViewerControl.Services);
                modelViewerControl.SetAxisFont(contentLoad.GetFont("Axis"));
            }
            showAxesMenuItem.Checked = show;
            modelViewerControl.ShowAxes = show;
        }


        private void wireframeItem_Click(object sender, EventArgs e)
        {
            wireframeItem.Checked = !wireframeItem.Checked;
            modelViewerControl.WireFrameEnable(wireframeItem.Checked);
        }

        private void invertYControlsItem_Click(object sender, EventArgs e)
        {
            invertYControlsItem.Checked = !invertYControlsItem.Checked;
            modelViewerControl.InvertY = invertYControlsItem.Checked;
        }

        private void helpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            HelpForm aForm = new HelpForm();
            aForm.ShowDialog();
            PauseGameInput(false);
        }

        private void featuresToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            FeaturesForm aForm = new FeaturesForm();
            aForm.ShowDialog();
            PauseGameInput(false);
        }

        private void synchroniseEmittersMenu_Click(object sender, EventArgs e)
        {
            modelViewerControl.SynchroniseEmitters();
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Menu Visibility
        //
        public void UpdateMenuItemVisibility()
        {
            WhatLighting();
        }

        private void WhatLighting()
        {
            light1EnabledToolStripMenuItem.Checked = modelViewerControl.Light1Enabled;
            light2EnabledToolStripMenuItem.Checked = modelViewerControl.Light2Enabled;
            reverseLightingToolStripMenuItem.Checked = modelViewerControl.ReverseLighting;
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Tools

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            OptionsForm aForm = new OptionsForm();
            aForm.MovementSpeed = modelViewerControl.CurrentMoveSpeed;
            aForm.TurnSpeed = modelViewerControl.CurrentTurnSpeed;
            aForm.GridSquareWidth = modelViewerControl.GridSquareWidth.ToString();
            DialogResult diagResult = aForm.ShowDialog();
            if (diagResult == DialogResult.OK)
            {
                modelViewerControl.CurrentMoveSpeed = aForm.MovementSpeed;
                modelViewerControl.CurrentTurnSpeed = aForm.TurnSpeed;
            }
            PauseGameInput(false);
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region File Helpers
        //
        /// <summary>
        /// See also DefaultFileFolder
        /// </summary>
        public static string GetSavePath()
        {
            string result = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                GlobalSettings.pathSaveGameFolder, GlobalSettings.pathSaveDataFolder);
            if (!Directory.Exists(result))
            {
                Directory.CreateDirectory(result);
            }
            return result;
        }
        /// <summary>
        /// Creates a relative path from one file
        /// or folder to another.
        /// http://weblogs.asp.net/pwelter34/archive/2006/02/08/create-a-relative-path-code-snippet.aspx
        /// </summary>
        /// <param name="fromDirectory">
        /// Contains the directory that defines the 
        /// start of the relative path.
        /// </param>
        /// <param name="toPath">
        /// Contains the path that defines the
        /// endpoint of the relative path.
        /// </param>
        /// <returns>
        /// The relative path from the start
        /// directory to the end path.
        /// </returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static string RelativePathTo(
            string fromDirectory, string toPath)
        {
            if (fromDirectory == null)
            {
                throw new ArgumentNullException("fromDirectory");
            }

            if (toPath == null)
            {
                throw new ArgumentNullException("toPath");
            }

            bool isRooted = Path.IsPathRooted(fromDirectory) && Path.IsPathRooted(toPath);

            if (isRooted)
            {
                bool isDifferentRoot = string.Compare(
                    Path.GetPathRoot(fromDirectory),
                    Path.GetPathRoot(toPath), true) != 0;

                if (isDifferentRoot)
                {
                    return toPath;
                }
            }

            StringCollection relativePath = new StringCollection();

            string[] fromDirectories = fromDirectory.Split(
                Path.DirectorySeparatorChar);

            string[] toDirectories = toPath.Split(
                Path.DirectorySeparatorChar);

            int length = Math.Min(
                fromDirectories.Length,
                toDirectories.Length);

            int lastCommonRoot = -1;

            // find common root
            for (int x = 0; x < length; x++)
            {
                if (string.Compare(fromDirectories[x],
                    toDirectories[x], true) != 0)
                {
                    break;
                }

                lastCommonRoot = x;
            }

            if (lastCommonRoot == -1)
            {
                return toPath;
            }

            // add relative folders in from path
            for (int x = lastCommonRoot + 1; x < fromDirectories.Length; x++)
            {
                if (fromDirectories[x].Length > 0)
                {
                    relativePath.Add("..");
                }
            }

            // add to folders to path
            for (int x = lastCommonRoot + 1; x < toDirectories.Length; x++)
            {
                relativePath.Add(toDirectories[x]);
            }

            // create relative path
            string[] relativeParts = new string[relativePath.Count];
            relativePath.CopyTo(relativeParts, 0);

            string newPath = string.Join(
                Path.DirectorySeparatorChar.ToString(),
                relativeParts);

            return newPath;
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Colours and Lighting

        public void SetMaterialColours(float specularPower, Vector3 specularColour, Vector3 diffuseColour, Vector3 emissiveColour)
        {
            modelViewerControl.SpecularPower = specularPower;
            modelViewerControl.SpecularColour = specularColour;
            modelViewerControl.DiffuseColour = diffuseColour;
            modelViewerControl.EmissiveColour = emissiveColour;
        }

        private void light1EnabledToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.Light1Enabled = !modelViewerControl.Light1Enabled;
            light1EnabledToolStripMenuItem.Checked = modelViewerControl.Light1Enabled;
        }

        private void light2EnabledToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.Light2Enabled = !modelViewerControl.Light2Enabled;
            light2EnabledToolStripMenuItem.Checked = modelViewerControl.Light2Enabled;
        }

        private void reverseLightingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.ReverseLighting = !modelViewerControl.ReverseLighting;
            reverseLightingToolStripMenuItem.Checked = modelViewerControl.ReverseLighting;
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Image Display
        //
        private void comboImageName_SelectedIndexChanged(object sender, EventArgs e)
        {
            ChangeImageToTheSelectedName();
        }
        /// <summary>
        /// Display the selected image.
        /// </summary>
        private void ChangeImageToTheSelectedName()
        {
            string withName = (string)comboImageName.SelectedValue;
            DisplayImage(modelViewerControl.GetImage(withName));
        }

        private void modelViewerControl_OnChangedImages(object sender, EventArgs e)
        {
            UpdateImagesList();
        }

        /// <summary>
        /// Set that the names on the image combo box to match the list of images.
        /// </summary>
        private void UpdateImagesList()
        {
            List<ParticleImage> images = modelViewerControl.Images;
            if (images == null)
            {
                return;
            }
            string currentText = (string)comboImageName.SelectedItem;
            comboImageName.Items.Clear();
            foreach (ParticleImage pItem in images)
            {
                comboImageName.Items.Add(pItem.Name);
            }
            DisplayImage(currentText);
        }
        /// <summary>
        /// Change the combo box to display the name if it exists.
        /// Leaves it unchanged if the new name does not exist in the list.
        /// Changes the image shown.
        /// </summary>
        private void DisplayImage(string withName)
        {
            if (!string.IsNullOrEmpty(withName) && comboImageName.Items.Contains(withName))
            {
                comboImageName.SelectedItem = withName;
                ParticleImage pImage = modelViewerControl.GetImage(withName);
                DisplayImage(pImage.Image);
            }
        }
        /// <summary>
        /// Display the texture on the form.
        /// </summary>
        private void DisplayImage(ParticleImage pTexture)
        {
            if (pTexture != null)
            {
                DisplayImage(pTexture.Name);
            }
        }
        /// <summary>
        /// Display the texture on the form.
        /// </summary>
        private void DisplayImage(Texture2D texture)
        {
            if (texture != null)
            {
                pictureTexture.Image = ImageHelper.Texture2Image(texture);
            }
        }

        private void buttonGrey_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonGrey.BackColor;
        }

        private void buttonBlack_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonBlack.BackColor;
        }

        private void buttonWhite_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonWhite.BackColor;
        }

        private void buttonBlue_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonBlue.BackColor;
        }

        private void buttonGreen_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonGreen.BackColor;
        }

        private void buttonAmber_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonAmber.BackColor;
        }

        private void buttonBrown_Click(object sender, EventArgs e)
        {
            pictureTexture.BackColor = buttonBrown.BackColor;
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region View Style

        private void buttonSkyDefault_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetBackgroundDefault();
        }

        private void buttonSkyGrey_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetBackgroundColour(buttonSkyGrey.BackColor.R, buttonSkyGrey.BackColor.G, buttonSkyGrey.BackColor.B);
        }

        private void buttonSkyGreen_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetBackgroundColour(buttonSkyGreen.BackColor.R, buttonSkyGreen.BackColor.G, buttonSkyGreen.BackColor.B);
        }

        private void colourSkyCustom_ColourChanged(object sender, EventArgs e)
        {
            modelViewerControl.SetBackgroundColour(colourSkyCustom.Colour);
        }

        private void buttonFloorDefault_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetFloorDefaultColour();
        }

        private void buttonFloorGrey_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetFloorColour(buttonFloorGrey.BackColor.R, buttonFloorGrey.BackColor.G, buttonFloorGrey.BackColor.B);
        }

        private void buttonFloorGreen_Click(object sender, EventArgs e)
        {
            modelViewerControl.SetFloorColour(buttonFloorGreen.BackColor.R, buttonFloorGreen.BackColor.G, buttonFloorGreen.BackColor.B);
        }

        private void colourFloorCustom_ColourChanged(object sender, EventArgs e)
        {
            modelViewerControl.SetFloorColour(colourFloorCustom.Colour);
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region Particle Settings
        //

        private void comboEffectName_SelectedIndexChanged(object sender, EventArgs e)
        {
            ParticleHolder holder = modelViewerControl.GetParticleHolder(CurrentEffectName());
            if (holder != null)
            {
                FormSettings(holder);
            }
        }

        private void addAParticleEffectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            ParticleNameForm aForm = new ParticleNameForm();
            aForm.ParticleName = "";
            aForm.ShowDialog();
            if (aForm.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                string name = aForm.ParticleName;
                string newName = name;
                int number = 0;
                while (modelViewerControl.IsParticleNameExists(newName))
                {
                    newName = name + ParseData.IntToString(number);
                    number++;
                }
                ParticleSettings settings = FormSettings();
                AddAndDisplayNewSettings(newName, FormSettings(), modelViewerControl.GetImage(settings.TextureName));
            }
            PauseGameInput(false);
        }


        private void renameEffectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            ParticleNameForm aForm = new ParticleNameForm();
            string oldName = CurrentEffectName(); ;
            aForm.ParticleName = oldName;
            aForm.ShowDialog();
            if (aForm.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                string name = aForm.ParticleName;
                string newName = name;
                if (oldName != newName)
                {
                    int number = 0;
                    while (modelViewerControl.IsParticleNameExists(newName))
                    {
                        newName = name + ParseData.IntToString(number);
                        number++;
                    }
                    modelViewerControl.RenameParticle(oldName, newName);
                    Thread.Sleep(2);
                    ChangeSelectedParticleName(newName);
                }
            }
            PauseGameInput(false);
        }

        private void modelViewerControl_OnChangedParticles(object sender, EventArgs e)
        {
            UpdateParticleList();
        }

        /// <summary>
        /// Set that the names on the image combo box to match the list of images.
        /// </summary>
        private void UpdateParticleList()
        {
            List<ParticleHolder> parts = modelViewerControl.Particles;
            if (parts == null)
            {
                return;
            }
            string currentText = (string)comboEffectName.SelectedItem;
            comboEffectName.Items.Clear();
            foreach (ParticleHolder pItem in parts)
            {
                comboEffectName.Items.Add(pItem.UniqueName);
            }
            ChangeSelectedParticleName(currentText);
        }
        /// <summary>
        /// Change the combo box to display the name if it exists.
        /// Leaves it unchanged if the new name does not exist in the list.
        /// Changes the particle settings shown.
        /// </summary>
        private void ChangeSelectedParticleName(string newName)
        {
                ParticleHolder holder = modelViewerControl.GetParticleHolder(newName);
                if (holder != null)
                {
                    FormSettings(holder);
                }
        }


        /// <summary>
        /// Return the name of the currently displayed settings.
        /// </summary>
        private string CurrentEffectName()
        {
            return (string)comboEffectName.SelectedItem;
        }
        /// <summary>
        /// True if the box on the form is ticked.
        /// </summary>
        private bool IsCurrentEffectEnabled()
        {
            return checkParticleEnabled.Checked;
        }

        /// <summary>
        /// Return the name of the currently displayed emitter.
        /// </summary>
        private string CurrentEmitterName()
        {
            return (string)comboEmitterName.SelectedItem;
        }

        /// <summary>
        /// Return the name of the currently displayed emitter to use for the particle.
        /// </summary>
        private string CurrentEmitterToUse()
        {
            return (string)comboEmitterToUse.SelectedItem;
        }

        private void buttonApplyEffect_Click(object sender, EventArgs e)
        {
            modelViewerControl.ChangeParticles(CurrentEffectName(), FormSettings(), IsCurrentEffectEnabled(), CurrentEmitterToUse());
        }

        /// <summary>
        /// Change all the settings and update the display and form to match the changes.
        /// </summary>
        private string AddAndDisplayNewSettings(string newName, ParticleSettings settings, ParticleImage pImage)
        {
            newName = Path.GetFileNameWithoutExtension(newName);
            ParticleHolder holder = modelViewerControl.AddNewParticles(newName, settings, pImage, CurrentEmitterName());
            if (holder == null)
            {
                return "Particle Effect Not Loaded!";
            }
            FormSettings(holder);
            return "";
        }

        /// <summary>
        /// Get the particle settings from the entries in the form.
        /// </summary>
        private ParticleSettings FormSettings()
        {
            ParticleSettings settings = new ParticleSettings();
            settings.TextureName = (string)comboImageName.SelectedItem;
            settings.MaxParticles = (int)numericMaxParticles.Value;
            settings.Duration = TimeSpan.FromSeconds((double)numericDurationSeconds.Value);
            settings.DurationRandomness = (float)numericRandomness.Value;
            settings.EmitterVelocitySensitivity = (float)numericEmitterSensitivity.Value;
            settings.MinHorizontalVelocity = (float)numericMinHorizontal.Value;
            settings.MaxHorizontalVelocity = (float)numericMaxHorizontal.Value;
            settings.MinVerticalVelocity = (float)numericMinVertical.Value;
            settings.MaxVerticalVelocity = (float)numericMaxVertical.Value;
            settings.Gravity = vectorGravity.Value;
            settings.EndVelocity = (float)numericEndVelocity.Value;
            settings.MinColor = colourMinimum.Colour;
            settings.MaxColor = colourMaximum.Colour;
            settings.FadeFactor = (float)numericFade.Value;
            settings.MinRotateSpeed = (float)numericMinRotate.Value;
            settings.MaxRotateSpeed = (float)numericMaxRotate.Value;
            settings.MinStartSize = (float)numericMinStartSize.Value;
            settings.MaxStartSize = (float)numericMaxStartSize.Value;
            settings.MinEndSize = (float)numericMinEndSize.Value;
            settings.MaxEndSize = (float)numericMaxEndSize.Value;
            settings.BlendStateSerializationHelper = comboBlendState.Text;
            return settings;
        }
        /// <summary>
        /// Set the dialogue boxes in the form to be the same as the settings.
        /// </summary>
        private void FormSettings(ParticleHolder holder)
        {
            if (holder == null)
            {
                return;
            }
            ParticleSettings settings = holder.GetParticleSettings();
            if (settings == null || string.IsNullOrEmpty(holder.UniqueName))
            {
                return;
            }
            if (!comboEffectName.Items.Contains(holder.UniqueName))
            {
                comboEffectName.Items.Add(holder.UniqueName);
            }
            comboEffectName.SelectedItem = holder.UniqueName;
            checkParticleEnabled.Checked = holder.Enabled;
            ChangeEmitterToUse(holder.GetEmitterName());
            numericMaxParticles.Value = (decimal)settings.MaxParticles;
            numericDurationSeconds.Value = (decimal)settings.Duration.TotalSeconds;
            numericRandomness.Value = (decimal)settings.DurationRandomness;
            numericEmitterSensitivity.Value = (decimal)settings.EmitterVelocitySensitivity;
            numericMinHorizontal.Value = (decimal)settings.MinHorizontalVelocity;
            numericMaxHorizontal.Value = (decimal)settings.MaxHorizontalVelocity;
            numericMinVertical.Value = (decimal)settings.MinVerticalVelocity;
            numericMaxVertical.Value = (decimal)settings.MaxVerticalVelocity;
            vectorGravity.Value = settings.Gravity;
            numericEndVelocity.Value = (decimal)settings.EndVelocity;
            colourMinimum.Colour = settings.MinColor;
            colourMaximum.Colour = settings.MaxColor;
            numericFade.Value = (decimal)settings.FadeFactor;
            numericMinRotate.Value = (decimal)settings.MinRotateSpeed;
            numericMaxRotate.Value = (decimal)settings.MaxRotateSpeed;
            numericMinStartSize.Value = (decimal)settings.MinStartSize;
            numericMaxStartSize.Value = (decimal)settings.MaxStartSize;
            numericMinEndSize.Value = (decimal)settings.MinEndSize;
            numericMaxEndSize.Value = (decimal)settings.MaxEndSize;
            comboBlendState.Text = settings.BlendStateSerializationHelper;
            DisplayImage(holder.GetTextureName());
        }

        private void buttonSmokeGravity_Click(object sender, EventArgs e)
        {
            vectorGravity.Value = new Vector3(-2.0f, -0.5f, 0);
        }

        private void buttonFireGravity_Click(object sender, EventArgs e)
        {
            vectorGravity.Value = new Vector3(0, 1.5f, 0);
        }

        private void buttonNoGravity_Click(object sender, EventArgs e)
        {
            vectorGravity.Value = Vector3.Zero;
        }


        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region Emitter
        //
        private void addAnEmitterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ParticleEmitter emit = modelViewerControl.GetNewEmitter();
            ChangeSelectedEmitter(emit.ID);
        }

        private void modelViewerControl_OnChangedEmitters(object sender, EventArgs e)
        {
            UpdateEmitterList();
        }

        private void UpdateEmitterList()
        {
            List<ParticleEmitter> emits = modelViewerControl.Emitters;
            if (emits == null)
            {
                return;
            }
            string currentText = (string)comboEmitterName.SelectedItem;
            string currentToUse = (string)comboEmitterToUse.SelectedItem;
            comboEmitterName.Items.Clear();
            comboEmitterToUse.Items.Clear();
            foreach (ParticleEmitter pItem in emits)
            {
                comboEmitterName.Items.Add(pItem.ID);
                comboEmitterToUse.Items.Add(pItem.ID);
            }
            if (!string.IsNullOrEmpty(currentText) && comboEmitterName.Items.Contains(currentText))
            {
                comboEmitterName.SelectedItem = currentText;
            }
            ChangeEmitterToUse(currentToUse);
        }
        /// <summary>
        /// Change the currently selected particle effect to use a different emitter.
        /// </summary>
        private void ChangeEmitterToUse(string newName)
        {
            if (!string.IsNullOrEmpty(newName) && comboEmitterToUse.Items.Contains(newName))
            {
                comboEmitterToUse.SelectedItem = newName;
            }
        }

        /// <summary>
        /// Change the currently selected emitter on the emitter panel.
        /// </summary>
        private void ChangeSelectedEmitter(string newName)
        {
            if (!string.IsNullOrEmpty(newName) && comboEmitterName.Items.Contains(newName))
            {
                ParticleEmitter pEmit = modelViewerControl.GetEmitter(newName);
                FormFromEmitter(pEmit);
            }
        }

        private void InitialiseEmitterValues()
        {
            if (comboEmitterName.Items.Count > 0)
            {
                string name = (string)comboEmitterName.Items[0];
                ChangeSelectedEmitter(name);
            }

            //modelViewerControl.ChangeEmitterSettings(EmitterFromForm(CurrentEmitterName()));
        }

        private void menuShowEmitterLocation_Click(object sender, EventArgs e)
        {
            modelViewerControl.ShowEmitterLocation = !menuShowEmitterLocation.Checked;
            menuShowEmitterLocation.Checked = modelViewerControl.ShowEmitterLocation;
        }

        private void buttonProjectile_Click(object sender, EventArgs e)
        {
            SetMotion(ParticleEmitter.EmitterMotion.Line);
            comboFlow.SelectedItem = comboFlow.Items[0];
            numericTriggerFrequency.Value = 0.4m;
            numericTriggerDuration.Value = 0.01667m;
            numericSpeed.Value = 200.0m;
            numericPartsPerSecond.Value = 350.0m;
        }

        private void buttonSmoke_Click(object sender, EventArgs e)
        {
            SetMotion(ParticleEmitter.EmitterMotion.Static);
            comboFlow.SelectedItem = comboFlow.Items[0];
            numericTriggerFrequency.Value = 2.0m;
            numericTriggerDuration.Value = 0.01667m;
            numericSpeed.Value = 1.0m;
            numericPartsPerSecond.Value = 30.0m;
        }

        private void buttonApplyEmitter_Click(object sender, EventArgs e)
        {
            modelViewerControl.ChangeOrAddEmitterSettings(EmitterFromForm(CurrentEmitterName()));
        }
        /// <summary>
        /// Returns a new particle emitter based on the form settings
        /// </summary>
        /// <returns></returns>
        private ParticleEmitter EmitterFromForm(string withName)
        {
            return new ParticleEmitter(withName,
                MotionSetting(),
                FlowSetting(),
                (float)numericPartsPerSecond.Value,
                (float)numericSpeed.Value,
                (float)numericTriggerFrequency.Value,
                (float)numericTriggerDuration.Value);

        }
        /// <summary>
        /// Update the form values from the settings.
        /// </summary>
        private void FormFromEmitter(ParticleEmitter pEmit)
        {
            if (pEmit == null || string.IsNullOrEmpty(pEmit.ID))
            {
                return;
            }
            if (!comboEmitterName.Items.Contains(pEmit.ID))
            {
                comboEmitterName.Items.Add(pEmit.ID);
            }
            comboEmitterName.SelectedItem = pEmit.ID;
            SetMotion(pEmit.Motion);
            SetFlow(pEmit.EmitFlow);
            numericPartsPerSecond.Value = (decimal)pEmit.ParticlesPerSecond;
            numericSpeed.Value = (decimal)pEmit.Speed;
            numericTriggerFrequency.Value = (decimal)pEmit.EmitFrequency;
            numericTriggerDuration.Value = (decimal)pEmit.EmitDuration;
        }
        /// <summary>
        /// Set the form combo based on the setting required.
        /// </summary>
        private void SetMotion(ParticleEmitter.EmitterMotion motion)
        {
            if (motion == ParticleEmitter.EmitterMotion.Static)
            {
                comboMotion.SelectedItem = comboMotion.Items[0];
            }
            else if (motion == ParticleEmitter.EmitterMotion.Line)
            {
                comboMotion.SelectedItem = comboMotion.Items[1];
            }
            else
            {
                comboMotion.SelectedItem = comboMotion.Items[2];
            }
        }
        /// <summary>
        /// Return the motion setting from the form combo box.
        /// </summary>
        private ParticleEmitter.EmitterMotion MotionSetting()
        {
            if (comboMotion.SelectedItem == comboMotion.Items[0])
            {
                return ParticleEmitter.EmitterMotion.Static;
            }
            else if (comboMotion.SelectedItem == comboMotion.Items[1])
            {
                return ParticleEmitter.EmitterMotion.Line;
            }
            return ParticleEmitter.EmitterMotion.Circle;
        }
        /// <summary>
        /// Set the form combo based on the setting required.
        /// </summary>
        private void SetFlow(ParticleEmitter.EmitterFlow flow)
        {
            if (flow == ParticleEmitter.EmitterFlow.Periodic)
            {
                comboFlow.SelectedItem = comboFlow.Items[1];
            }
            else
            {
                comboFlow.SelectedItem = comboFlow.Items[0];
            }
        }
        /// <summary>
        /// Return the flow setting from the form combo box.
        /// </summary>
        private ParticleEmitter.EmitterFlow FlowSetting()
        {
            if (comboFlow.SelectedItem == comboFlow.Items[1])
            {
                return ParticleEmitter.EmitterFlow.Periodic;
            }
            return ParticleEmitter.EmitterFlow.Continuous;
        }

        private void comboEmitterName_SelectedIndexChanged(object sender, EventArgs e)
        {
            ParticleEmitter pEmit = modelViewerControl.GetEmitter(CurrentEmitterName());
            FormFromEmitter(pEmit);
        }
        //
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

    }
}
